package com.test.io.nio.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;

/**
 * describe: NIO服务端
 *
 * @author lianying
 * @date 2020/01/22
 */
public class NioServer {
    private ServerSocketChannel serverSocketChannel=null;
    private int port;
    private Selector selector;
    public NioServer(int port){
        this.port=port;
    }

    public void start(){
        if(serverSocketChannel!=null)
        {
            System.out.println("服务已启动,无需重复启动");
            return;
        }
        try {
            selector=Selector.open();
            serverSocketChannel=ServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress(port));
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
            System.out.println("服务启动成功");
            while (true)
            {
                Thread.sleep(100);
                int count=selector.select();
                if(count==0)
                {
                    continue;
                }
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                for (int i = 0; i < selectionKeys.size(); i++) {
                    Iterator<SelectionKey> iterator = selectionKeys.iterator();
                    while (iterator.hasNext())
                    {
                        SelectionKey next = iterator.next();
                        iterator.remove();
                        if(next.isAcceptable())
                        {
                            acceptHandler();
                        }
                        if(next.isReadable())
                        {
                            readHandler(next);
                        }
                    }
                }
            }
        } catch (IOException e) {
            System.out.println("服务启动失败");
            serverSocketChannel=null;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void readHandler(SelectionKey selectionKey) throws IOException {
        //读取数据进行群发
        SocketChannel accept= (SocketChannel) selectionKey.channel();
        ByteBuffer byteBuffer=ByteBuffer.allocate(1024);
        String request="";
        while (accept.read(byteBuffer)>0)
        {
            byteBuffer.flip();
            request+=Charset.forName("UTF-8").decode(byteBuffer);
        }
        System.out.println("服务端收到消息并进行转发："+request);
        //遍历所有连接，非本连接的进行转发。
        Set<SelectionKey> keys = selector.keys();
        Iterator<SelectionKey> iterator = keys.iterator();
        while (iterator.hasNext())
        {
            SelectionKey next = iterator.next();
            Channel channel = next.channel();
            if(channel instanceof SocketChannel&&channel!=accept)
            {
                SocketChannel socketChannel= (SocketChannel) channel;
                socketChannel.write(Charset.forName("UTF-8").encode(request));
            }
        }
    }

    private void acceptHandler() throws IOException {
        SocketChannel accept= serverSocketChannel.accept();
        accept.configureBlocking(false);
        ByteBuffer buffer= Charset.forName("UTF-8").encode("已连接至多人聊天服务器");
        accept.write(buffer);
        accept.register(selector,SelectionKey.OP_READ);
    }

    public static void main(String [] args)
    {
        NioServer nioServer=new NioServer(10022);
        nioServer.start();
    }
}
